/*
 * CDBUS协议实现
 * 
 * 功能描述：
 * 实现CDBUS通信协议的核心功能，包括帧解析、CRC校验、地址过滤等
 * 支持多节点通信，提供可靠的数据传输机制
 * 
 * 协议特点：
 * - 基于主从架构的多节点通信协议
 * - 支持单播、广播和组播通信模式
 * - 使用Modbus CRC16进行数据完整性校验
 * - 最大支持253字节用户数据
 * 
 * 帧格式：
 * [源地址1字节][目标地址1字节][数据长度1字节][数据N字节][CRC16 2字节]
 * 
 * 版权信息：
 * Copyright (c) 2024
 * 基于CDBUS协议规范实现
 */

#include "cdbus.h"
#include "modbus_crc.h"
#include <string.h>

/**
 * @brief 初始化CDBUS协议实例
 * @param cdbus CDBUS实例指针
 * @param address 本节点地址（0-254）
 * 
 * @note 地址255为广播地址，不可用作节点地址
 * @note 默认过滤器设置为接收所有消息（广播地址）
 * 
 * 初始化内容包括：
 * - 清零所有状态变量
 * - 设置节点地址
 * - 配置默认过滤器
 * - 设置状态机为空闲状态
 */
/**
 * @brief 初始化CDBUS协议实例
 * @param cdbus CDBUS实例指针
 * @param address 本节点地址（0-254）
 * 
 * @note 地址255为广播地址，不可用作节点地址
 * @note 默认过滤器设置为接收所有消息（广播地址）
 * 
 * 初始化内容包括：
 * - 清零所有状态变量
 * - 设置节点地址
 * - 配置默认过滤器
 * - 设置状态机为空闲状态
 */
void cdbus_init(cdbus_t *cdbus, uint8_t address) {
    memset(cdbus, 0, sizeof(cdbus_t));
    cdbus->address = address;
    cdbus->filter = CDBUS_BROADCAST_ADDR;  // 默认接收所有消息
    cdbus->state = CDBUS_STATE_IDLE;
}

/**
 * @brief 设置地址过滤器
 * @param cdbus CDBUS实例指针
 * @param filter 过滤器地址
 * 
 * @note 设置为CDBUS_BROADCAST_ADDR时接收所有消息
 * @note 设置为特定地址时只接收该地址和广播消息
 */
void cdbus_set_filter(cdbus_t *cdbus, uint8_t filter) {
    cdbus->filter = filter;
}

/**
 * @brief 重置CDBUS接收状态机
 * @param cdbus CDBUS实例指针
 * 
 * @note 在发生错误或处理完一帧数据后调用
 * @note 重置后状态机回到空闲状态，准备接收新帧
 */
void cdbus_reset(cdbus_t *cdbus) {
    cdbus->state = CDBUS_STATE_IDLE;
    cdbus->rx_index = 0;
    cdbus->expected_len = 0;
}

/**
 * @brief 处理接收到的单个字节数据
 * @param cdbus CDBUS实例指针
 * @param byte 接收到的字节数据
 * @return 
 *   - 0: 继续接收，帧未完整
 *   - 1: 成功接收到完整帧
 *   - -1: 接收错误（帧长超出限制或CRC校验失败）
 * 
 * @note 该函数实现了CDBUS协议的状态机，逐字节处理接收数据
 * @note 支持最大256字节帧，其中用户数据最多253字节
 * 
 * 状态机流程：
 * - IDLE -> RECEIVING: 接收到帧起始字节
 * - RECEIVING: 持续接收数据，计算帧长度和CRC
 * - COMPLETE: 接收到完整有效帧
 * - ERROR: 接收错误，需重置状态机
 */
int cdbus_process_byte(cdbus_t *cdbus, uint8_t byte) {
    switch (cdbus->state) {
        case CDBUS_STATE_IDLE:
            /* 接收到帧起始，开始新的接收过程 */
            cdbus->rx_buffer[0] = byte;
            cdbus->rx_index = 1;
            cdbus->state = CDBUS_STATE_RECEIVING;
            break;
            
        case CDBUS_STATE_RECEIVING:
            /* 接收数据，检查缓冲区溢出 */
            if (cdbus->rx_index < CDBUS_MAX_FRAME_SIZE) {
                cdbus->rx_buffer[cdbus->rx_index++] = byte;
            }
            
            /* 接收到帧头，解析数据长度 */
            if (cdbus->rx_index == 3) {
                cdbus->expected_len = cdbus->rx_buffer[CDBUS_LEN_OFFSET] + 
                                    CDBUS_HEADER_SIZE + CDBUS_CRC_SIZE;
                if (cdbus->expected_len > CDBUS_MAX_FRAME_SIZE) {
                    cdbus->state = CDBUS_STATE_ERROR;
                    return -1;  /* 帧长超出限制 */
                }
            }
            
            /* 接收到完整帧，进行CRC校验 */
            if (cdbus->expected_len > 0 && cdbus->rx_index >= cdbus->expected_len) {
                uint16_t received_crc = (cdbus->rx_buffer[cdbus->expected_len - 2] << 8) |
                                      cdbus->rx_buffer[cdbus->expected_len - 1];
                uint16_t calculated_crc = modbus_crc16(cdbus->rx_buffer, 
                                                       cdbus->expected_len - 2);
                
                if (received_crc == calculated_crc) {
                    /* CRC校验通过，检查地址过滤 */
                    uint8_t dst_addr = cdbus->rx_buffer[CDBUS_DST_OFFSET];
                    
                    /* 地址匹配检查：广播地址、本机地址或过滤器为广播地址 */
                    if (dst_addr == CDBUS_BROADCAST_ADDR || 
                        dst_addr == cdbus->address ||
                        cdbus->filter == CDBUS_BROADCAST_ADDR) {
                        
                        /* 复制有效帧数据到帧缓冲区 */
                        cdbus->frame.src_addr = cdbus->rx_buffer[CDBUS_SRC_OFFSET];
                        cdbus->frame.dst_addr = dst_addr;
                        cdbus->frame.data_len = cdbus->rx_buffer[CDBUS_LEN_OFFSET];
                        memcpy(cdbus->frame.data, 
                               &cdbus->rx_buffer[CDBUS_DATA_OFFSET], 
                               cdbus->frame.data_len);
                        cdbus->frame.crc = received_crc;
                        
                        cdbus->state = CDBUS_STATE_COMPLETE;
                        return 1;  /* 成功接收到完整帧 */
                    }
                }
                
                /* CRC校验失败或地址不匹配，重置状态机 */
                cdbus_reset(cdbus);
                return -1;
            }
            break;
            
        case CDBUS_STATE_COMPLETE:
        case CDBUS_STATE_ERROR:
            /* 状态机处于终止状态，重置后处理新数据 */
            cdbus_reset(cdbus);
            break;
    }
    
    return 0;  /* 继续接收数据 */
}

/**
 * @brief 获取接收到的完整帧数据
 * @param cdbus CDBUS实例指针
 * @param frame 用于存储帧数据的缓冲区
 * @return 
 *   - 0: 成功获取帧数据
 *   - -1: 当前没有完整帧可用
 * 
 * @note 获取帧后状态机会自动重置为IDLE状态
 * @note 该函数非阻塞，立即返回当前状态
 */
int cdbus_get_frame(cdbus_t *cdbus, cdbus_frame_t *frame) {
    if (cdbus->state != CDBUS_STATE_COMPLETE) {
        return -1;
    }
    
    memcpy(frame, &cdbus->frame, sizeof(cdbus_frame_t));
    cdbus_reset(cdbus);
    return 0;
}

/**
 * @brief 创建CDBUS协议帧
 * @param src 源节点地址
 * @param dst 目标节点地址
 * @param data 用户数据缓冲区指针
 * @param len 用户数据长度（0-253字节）
 * @param buffer 用于存储完整帧的缓冲区（至少256字节）
 * @return 完整帧长度（字节数），失败返回-1
 * 
 * @note 缓冲区必须足够大以容纳完整帧
 * @note 自动计算并附加CRC16校验码
 * 
 * 帧格式：
 * [src][dst][len][data...][crc_high][crc_low]
 */
int cdbus_create_frame(uint8_t src, uint8_t dst, uint8_t *data, uint8_t len, uint8_t *buffer) {
    if (len > CDBUS_MAX_DATA_SIZE) {
        return -1;  /* 数据长度超出限制 */
    }
    
    /* 填充帧头 */
    buffer[CDBUS_SRC_OFFSET] = src;
    buffer[CDBUS_DST_OFFSET] = dst;
    buffer[CDBUS_LEN_OFFSET] = len;
    
    /* 填充用户数据 */
    if (len > 0 && data != NULL) {
        memcpy(&buffer[CDBUS_DATA_OFFSET], data, len);
    }
    
    /* 计算并附加CRC16校验码 */
    uint16_t crc = modbus_crc16(buffer, len + CDBUS_HEADER_SIZE);
    buffer[len + CDBUS_HEADER_SIZE] = (crc >> 8) & 0xFF;
    buffer[len + CDBUS_HEADER_SIZE + 1] = crc & 0xFF;
    
    return len + CDBUS_HEADER_SIZE + CDBUS_CRC_SIZE;
}

/**
 * @brief 计算数据的CRC16校验值
 * @param data 数据缓冲区指针
 * @param len 数据长度
 * @return CRC16校验值
 * 
 * @note 使用Modbus CRC16算法
 * @note 用于手动验证数据完整性
 */
uint16_t cdbus_calculate_crc(uint8_t *data, uint8_t len) {
    return modbus_crc16(data, len);
}